Skip to content

feat(screens): roster page with CRUD, sliders, double-exposure warning (T-033) - #9

Merged
BrandanBurgess merged 14 commits into
mainfrom
integration
Jul 16, 2026
Merged

feat(screens): roster page with CRUD, sliders, double-exposure warning (T-033)#9
BrandanBurgess merged 14 commits into
mainfrom
integration

Conversation

@BrandanBurgess

Copy link
Copy Markdown
Owner

T-033: Roster page (Brief §4 step 19)

Player CRUD (coach-only, API-enforced), role/work-rate chips, six attribute sliders, and the double-exposure fit warning computed server-side from the seeded role_clashes copy. Includes a latent-bug fix in api.ts (204 responses now drain the body, which also protects the pattern-delete path) and an Alembic migration 0003 adding Player.flank.

DoD (Brief §5, Screens + ticket rules)

  • Page matches PNGs 12, 20 across the three themes on desktop and phone frames; gold-only interactive; red never a call to action (fit banner is status styling, not a CTA)
  • Double-exposure warning fires when a High AWR fullback sits behind a High/Low winger on the same designed flank, and only renders for coaches
  • Coach-only enforcement in the API, not just UI: player-role GET /api/roster payload has NO fit_warnings key at all (backend test proves absence); player gets 403 on create/update/delete
  • All routes through the scoped query layer; write schema is extra=forbid with no team_id/user_id fields
  • All prior e2e intact; make verify green on integration post-merge (pytest 113, vitest 69, playwright 46 both viewports, em-dash scan, seed validator)

Founder question (flagged per CLAUDE.md rule 7, default shipped, not blocking)

Doc 03's schema has no flank column on players, but its own double-exposure rule requires knowing which side the winger and fullback share. Shipped default: nullable Player.flank (left/right/center) via migration 0003, mirroring the playstyle_note reconciliation precedent. Alternative if preferred: derive flank from formation slot assignments once those land. Confirm or redirect; also note is_you is wired but always false until a row-claiming flow exists (not in this ticket's scope).

🤖 Generated with Claude Code

BrandanBurgess and others added 14 commits July 16, 2026 02:39
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…T-030)

Whiteboard page (Brief step 16, PNG 01-05/14/34): toolbar, view menu
(zones + thresholds), record/replay, and save into My Patterns, all
persisted through the scoped query layer (backend/app/routers/whiteboard.py)
into the boards and saved_patterns rows (doc 03 4.2/4.3). Delete is
coach-only, enforced server-side (403 for players), and every saved
pattern is author-stamped from the caller's own membership, never a
client-supplied field.

Fixes a real reload bug: the view menu's settings popover floated above
the toolbar and, left open, could visually sit on top of a token (e.g.
the ball's default spot, or any token near the toolbar on a phone-width
board). A drag or click landing there hit the popover instead of the
token, and for a checkbox's label that silently flipped a zone toggle
the user never touched, which then persisted to the boards row on
reload. Fixed by closing the view menu when recording starts (a
deliberate mode switch) and, for phone-width boards where the popover
has no gap in the pitch it can occupy without covering some token,
pinning it to the viewport's top edge instead of floating over the
pitch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@BrandanBurgess
BrandanBurgess merged commit 4670dea into main Jul 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant